home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Games / xmris / monster.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  13KB  |  585 lines

  1. /*{{{  (C) 1992 Nathan Sidwell*/
  2. /*****************************************************************************
  3.             X M R I S V1.01
  4.             ---------------
  5.             (C) 1992 Nathan Sidwell
  6.  
  7. This program is copyright (C) 1992 Nathan Sidwell. This software and documentation
  8. is in the public domain. Permission is granted to distribute and compile
  9. verbatim copies of this software for non-commercial, non-profit use,
  10. without fee. The software may be modified, provided that both the above copyright
  11. notice and this permission notice appear.
  12.  
  13. No guarantee is given as to the robustness or suitability of this
  14. software for your computer.
  15.  
  16. Nathan Sidwell  INMOS UK |                 | nathan@inmos.co.uk       DoD#0390
  17. *****************************************************************************/
  18. /*}}}*/
  19. #include "xmris.h"
  20. /*{{{  prototypes*/
  21. static void extra_dies PROTOARGLIST((void));
  22. /*}}}*/
  23. /*{{{  MONSTER *extra_escape()*/
  24. extern MONSTER *extra_escape FUNCARGVOID
  25. /*
  26.  * remove the extra monster from the top, so it
  27.  * can run around
  28.  */
  29. {
  30.   int       x;
  31.   
  32.   extra.escape = 1;
  33.   x = XTRA_X + extra.select * XTRA_SPACING;
  34.   XFillRectangle(display.display, display.back, GCN(GC_CLEAR),
  35.       x, XTRA_Y, CELL_WIDTH, CELL_HEIGHT);
  36.   add_background(x, XTRA_Y, CELL_WIDTH, CELL_HEIGHT);
  37.   x -= BORDER_LEFT + GAP_WIDTH;
  38.   assert(x % (CELL_WIDTH + GAP_WIDTH) % VEL_X == 0);
  39.   return spawn_monster(2, 1, 1, x / (CELL_WIDTH + GAP_WIDTH), 0,
  40.       x % (CELL_WIDTH + GAP_WIDTH), XTRA_Y - BORDER_TOP);
  41. }
  42. /*}}}*/
  43. /*{{{  void extra_dies()*/
  44. static void extra_dies FUNCARGVOID
  45. /*
  46.  * the extra monster has died,
  47.  * put it back at the top
  48.  * and maybe alter the state
  49.  */
  50. {
  51.   unsigned  got;
  52.   
  53.   if(global.state == 2)
  54.     {
  55.       global.state = 3;
  56.       monster.den = 0;
  57.       monster.delay = 0;
  58.     }
  59.   got = extra.got & (1 << extra.select);
  60.   extra.got |= 1 << extra.select;
  61.   extra.escape = 0;
  62.   if(!got)
  63.     create_xtra_monster(extra.select);
  64.   draw_extra();
  65.   return;
  66. }
  67. /*}}}*/
  68. /*{{{  void fall_monsters()*/
  69. extern void fall_monsters FUNCARGVOID
  70. /*
  71.  * makes all the monsters fall
  72.  */
  73. {
  74.   unsigned  i;
  75.   MONSTER   *mptr;
  76.  
  77.   for(mptr = monster.list, i = monster.monsters; i--; mptr++)
  78.     if(mptr->apple)
  79.       {
  80.     /*{{{  just hit?*/
  81.     if(mptr->face < 8)
  82.       {
  83.         if(BOARDCELL(mptr->cell.x, mptr->cell.y)->distance ==
  84.           monster.nearest)
  85.         global.difficulty++;
  86.         new_face(mptr);
  87.         if(mptr == &monster.list[0])
  88.           mptr->shot = 1;
  89.         else
  90.           {
  91.         mptr->chew = 0;
  92.         if(mptr->type < 2)
  93.           monster.normals--;
  94.         else if(mptr->type == 2)
  95.           extra_dies();
  96.         else if(mptr->type == 3)
  97.           monster.drones--;
  98.           }
  99.       }
  100.     /*}}}*/
  101.     mptr->pixel.y = mptr->apple->pixel.y + CELL_HEIGHT;
  102.     if(mptr->apple && mptr->apple->state > 3)
  103.       {
  104.         if(mptr->type != 4)
  105.           mptr->type = 5;
  106.         else
  107.           mptr->apple = NULL;
  108.       }
  109.       }
  110.   return;
  111. }
  112. /*}}}*/
  113. /*{{{  void move_monsters()*/
  114. extern void move_monsters FUNCARGVOID
  115. /*
  116.  * moves all the monsters
  117.  */
  118. {
  119.   MONSTER   *mptr;
  120.   unsigned  i;
  121.   unsigned  nearest;
  122.   unsigned  farthest;
  123.  
  124.   nearest = 255;
  125.   farthest = 0;
  126.   for(mptr = &monster.list[1], i = monster.monsters - 1; i--; mptr++)
  127.     {
  128.       if(mptr->shot || (mptr->type == 3 && global.state == 3))
  129.     /*{{{  shot*/
  130.     {
  131.       if(BOARDCELL(mptr->cell.x, mptr->cell.y)->distance ==
  132.           monster.nearest)
  133.         global.difficulty++;
  134.       if(mptr->type < 2)
  135.         monster.normals--;
  136.       else
  137.         /*{{{  convert to apple*/
  138.         {
  139.           APPLE     *aptr;
  140.           CELL      *cptr;
  141.               
  142.           if(mptr->type == 2)
  143.         extra_dies();
  144.           else if(mptr->type == 3)
  145.         monster.drones--;
  146.           if(mptr->offset.x > (CELL_WIDTH + GAP_WIDTH) / 2)
  147.         {
  148.           mptr->offset.x -= CELL_WIDTH + GAP_WIDTH;
  149.           mptr->cell.x++;
  150.         }
  151.           else if(mptr->offset.x < -(CELL_WIDTH + GAP_WIDTH) / 2)
  152.         {
  153.           mptr->offset.x += CELL_WIDTH + GAP_WIDTH;
  154.           mptr->cell.x--;
  155.         }
  156.           cptr = BOARDCELL(mptr->cell.x, mptr->cell.y);
  157.           aptr = spawn_apple(mptr->cell.x, mptr->cell.y,
  158.           mptr->offset.x, mptr->offset.y);
  159.           if(mptr->cell.y == CELLS_DOWN - 1)
  160.         aptr->state = 2;
  161.           else if(mptr->offset.y < cptr->depths[1])
  162.         aptr->state = 2;
  163.           else if(!mptr->offset.y && cptr[CELL_STRIDE].visit)
  164.         {
  165.           aptr->state = 1;
  166.           aptr->count = APPLE_ROCK_DELAY;
  167.         }
  168.         }
  169.         /*}}}*/
  170.       if(mptr->shot)
  171.         add_score(500, mptr->pixel.x + CELL_WIDTH / 2,
  172.         mptr->pixel.y + CELL_HEIGHT / 2);
  173.       mptr->type = 5;
  174.     }
  175.     /*}}}*/
  176.       else if(mptr->apple)
  177.     /*EMPTY*/;
  178.       else if(mptr->chew)
  179.     /*{{{  chewing*/
  180.     {
  181.       if(mptr->chew == 1)
  182.         {
  183.           mptr->chew = 2;
  184.           mptr->count = CHOMP_DELAY;
  185.           mptr->image = 0;
  186.           mptr->cycle = MONSTER_CYCLES - 1;
  187.         }
  188.       mptr->count--;
  189.       if(!mptr->count)
  190.         mptr->chew = 0;
  191.       if(!mptr->cycle)
  192.         {
  193.           mptr->image = (mptr->image + 1) % MONSTER_IMAGES;
  194.           mptr->cycle = MONSTER_CYCLES;
  195.         }
  196.       mptr->cycle--;
  197.     }
  198.     /*}}}*/
  199.       else if(global.state != 4)
  200.     {
  201.       CELL      *cptr;
  202.  
  203.       cptr = BOARDCELL(mptr->cell.x, mptr->cell.y);
  204.       assert((cptr->distance || global.broken) && cptr->visit);
  205.       if(!mptr->cycle)
  206.         {
  207.           mptr->cycle = MONSTER_CYCLES;
  208.           mptr->image++;
  209.           if(mptr->image == MONSTER_IMAGES)
  210.         mptr->image = 0;
  211.         }
  212.       if((!mptr->count || mptr->type & 2) && !mptr->pause)
  213.         mptr->cycle--;
  214.       if(mptr->type & 2 || global.state != 2)
  215.         {
  216.           if(nearest > cptr->distance)
  217.         nearest = cptr->distance;
  218.           if(farthest < cptr->distance)
  219.         farthest = cptr->distance;
  220.         }
  221.       switch(mptr->type)
  222.       {
  223.         /*{{{  case 0: case 1: (normal or muncher)*/
  224.         case 0: case 1:
  225.         {
  226.           int     valid;
  227.               
  228.           valid = valid_directions(mptr, cptr);
  229.           if(mptr->count)
  230.         mptr->count--;
  231.           if(!mptr->type && random() < CONT_TOGGLE_PROB)
  232.         /*{{{  toggle the cont & maybe turn round*/
  233.         {
  234.           mptr->cont = !mptr->cont;
  235.           if(mptr->pause || mptr->stop)
  236.             {
  237.               mptr->dir ^= 1;
  238.               new_face(mptr);
  239.             }
  240.         }
  241.         /*}}}*/
  242.           if(mptr->push)
  243.         /*{{{  disable left or right*/
  244.         {
  245.           if(mptr->push < 0)
  246.             valid &= 0x77;
  247.           else
  248.             valid &= 0xBB;
  249.         }
  250.         /*}}}*/
  251.           else if(mptr->count)
  252.         valid = 0;
  253.           else if(mptr->pause)
  254.         {
  255.           if(!mptr->type)
  256.             {
  257.               if(random() < GO_MUNCH_PROB * global.difficulty)
  258.             mptr->gomunch = 1;
  259.               valid = 0;
  260.             }
  261.           else if(mptr->stop || random() < PUSH_TURN_PROB)
  262.             {
  263.               mptr->dir ^= 1;
  264.               new_face(mptr);
  265.               valid = 0;
  266.             }
  267.           mptr->stop = 0;
  268.           mptr->pause = 0;
  269.         }
  270.           else if(global.state == 2)
  271.         valid = 0;
  272.           else if(!mptr->offset.x && !mptr->offset.y)
  273.         {
  274.           mptr->fast = 0;
  275.           if(!mptr->type && global.state == 3)
  276.             mptr->fast = 1;
  277.           if(mptr->gomunch)
  278.             {
  279.               mptr->gomunch = 0;
  280.               mptr->type = 1;
  281.               mptr->count = GO_MUNCH_DELAY;
  282.             }
  283.           else if(mptr->type)
  284.             {
  285.               int       temp;
  286.             
  287.               temp = valid & 0xF;
  288.               if((temp & -temp) != temp)
  289.             {
  290.               APPLE     *aptr;
  291.               unsigned  i;
  292.               int       x;
  293.                       
  294.               mptr->type = 0;
  295.               mptr->count = STOP_MUNCH_DELAY;
  296.               valid = 0;
  297.               x = mptr->pixel.x - CELL_WIDTH + GAP_WIDTH * 2;
  298.               for(aptr = apple.list, i = apple.apples; i--; aptr++)
  299.                 {
  300.                   if(!aptr->state && aptr->pixel.x - x >= 0 &&
  301.                   aptr->pixel.x - x < CELL_WIDTH * 2 - GAP_WIDTH * 4 &&
  302.                   aptr->cell.y == mptr->cell.y - 1)
  303.                 {
  304.                   aptr->state = 1;
  305.                   aptr->count = APPLE_ROCK_DELAY;
  306.                 }
  307.                 }
  308.             }
  309.             }
  310.           else if(!mptr->type && random() <
  311.               GO_MUNCH_PROB * global.difficulty)
  312.             mptr->gomunch = 1;
  313.         }
  314.           if(!valid)
  315.         /*EMPTY*/;
  316.           else if(mptr->type)
  317.         /*{{{  move the muncher*/
  318.         {
  319.           if(mptr->offset.x || mptr->offset.y)
  320.             /*{{{  carry on*/
  321.             {
  322.               CELL      *nptr;
  323.                       
  324.               nptr = move_muncher(mptr);
  325.               if(nptr)
  326.             {
  327.               cptr = nptr;
  328.               if(nptr->sprite == SPRITE_CHERRY)
  329.                 {
  330.                   global.cherries--;
  331.                   nptr->sprite = 0;
  332.                 }
  333.             }
  334.             }
  335.             /*}}}*/
  336.           else
  337.             /*{{{  pick new direction*/
  338.             {
  339.               int     temp;
  340.                       
  341.               temp = ~valid & 0xF;
  342.               if(!mptr->cell.y)
  343.             temp &= 0xE;
  344.               else if(mptr->cell.y == CELLS_DOWN - 1)
  345.             temp &= 0xD;
  346.               if(!mptr->cell.x)
  347.             temp &= 0xB;
  348.               else if(mptr->cell.x == CELLS_ACROSS - 1)
  349.             temp &= 0x7;
  350.               if(!temp)
  351.             temp = valid & 0xF;
  352.               if(mptr->pixel.x < monster.list[0].pixel.x)
  353.             valid = 0x8;
  354.               else if(mptr->pixel.x > monster.list[0].pixel.x)
  355.             valid = 0x4;
  356.               else
  357.             valid = 0;
  358.               if(!(valid & temp))
  359.             {
  360.               if(mptr->pixel.y < monster.list[0].pixel.y)
  361.                 valid = 0x2;
  362.               else if(mptr->pixel.y > monster.list[0].pixel.y)
  363.                 valid = 0x1;
  364.               if(!(valid & temp))
  365.                 valid = temp;
  366.             }
  367.               assert(valid);
  368.               for(temp = 0; !(valid & 1); temp++)
  369.             valid >>= 1;
  370.               if(temp != mptr->dir)
  371.             {
  372.               mptr->dir = temp;
  373.               new_face(mptr);
  374.             }
  375.               move_muncher(mptr);
  376.             }
  377.             /*}}}*/
  378.         }
  379.         /*}}}*/
  380.           else
  381.         /*{{{  pick a direction*/
  382.         {
  383.           unsigned  temp;
  384.                   
  385.           if(mptr->cont)
  386.             {
  387.               valid &= 0xF;
  388.               temp = valid & ~(1 << (mptr->dir ^ 1));
  389.               if(temp)
  390.             valid = temp;
  391.             }
  392.           else if(valid & 0xF0)
  393.             valid = valid & valid >> 4;
  394.           valid = choose_direction(valid);
  395.           temp = mptr->dir;
  396.           if(valid != mptr->dir)
  397.             {
  398.               mptr->dir = valid;
  399.               if(mptr->push && (valid ^ temp) != 1)
  400.             {
  401.               mptr->push = 0;
  402.               mptr->cont = 1;
  403.             }
  404.               new_face(mptr);
  405.             }
  406.           if(!apple_stop(mptr, cptr))
  407.             cptr = move_movable(mptr, cptr);
  408.           if(mptr->push)
  409.             {
  410.               mptr->dir = temp;
  411.               mptr->push = 0;
  412.             }
  413.         }
  414.         /*}}}*/
  415.           break;
  416.         }
  417.         /*}}}*/
  418.         /*{{{  case 2: case 3: (xtra or drone)*/
  419.         case 2: case 3:
  420.         {
  421.           int     valid;
  422.           int     temp;
  423.               
  424.           /*{{{  giving birth?*/
  425.           if(monster.delay && mptr->type == 2 && global.state == 2)
  426.         {
  427.           monster.delay--;
  428.           if(monster.delay)
  429.             break;
  430.           if(monster.den)
  431.             {
  432.               monster.delay = XTRA_BIRTH_DELAY;
  433.               monster.den--;
  434.               spawn_monster(3, mptr->dir, mptr->face,
  435.               mptr->cell.x, mptr->cell.y,
  436.               mptr->offset.x, mptr->offset.y);
  437.               monster.drones++;
  438.               i++;
  439.             }
  440.         }
  441.           /*}}}*/
  442.           valid = valid_directions(mptr, cptr);
  443.           if(global.state == 3 && !mptr->offset.x && ! mptr->offset.y)
  444.         mptr->fast = 1;
  445.           /*{{{  pick a direction*/
  446.           {
  447.         if(valid & 0xF0 &&
  448.             (mptr->type != 2 || player.ball.state ||
  449.             (global.state == 2 ? mptr->count == monster.farthest :
  450.              mptr->count != monster.nearest)))
  451.           {
  452.             mptr->cont = 0;
  453.             valid >>= 4;
  454.           }
  455.         else
  456.           {
  457.             temp = valid & ((valid >> 4) ^ 0xF);
  458.             if(temp)
  459.               valid = temp;
  460.             else
  461.               valid &= 0xF;
  462.           }
  463.         valid = choose_direction(valid);
  464.         if(valid != mptr->dir)
  465.           {
  466.             mptr->dir = valid;
  467.             new_face(mptr);
  468.           }
  469.         mptr->count = cptr->distance;
  470.         cptr = move_movable(mptr, cptr);
  471.         /*{{{  walked into apple?*/
  472.         {
  473.           unsigned  i;
  474.           APPLE     *aptr;
  475.           int       x, y;
  476.           int       width, height;
  477.                   
  478.           x = mptr->pixel.x;
  479.           y = mptr->pixel.y;
  480.           /*{{{  set offset*/
  481.           if(mptr->dir & 2)
  482.             {
  483.               x -= CELL_WIDTH / 2;
  484.               y -= CELL_HEIGHT / 4;
  485.               width = CELL_WIDTH;
  486.               height = CELL_HEIGHT / 2;
  487.             }
  488.           else
  489.             {
  490.               x -= CELL_WIDTH / 4;
  491.               y -= CELL_HEIGHT / 2;
  492.               width = CELL_WIDTH / 2;
  493.               height = CELL_HEIGHT;
  494.             }
  495.           /*}}}*/
  496.           for(aptr = apple.list, i = apple.apples; i--; aptr++)
  497.             {
  498.               if(aptr->state < 3 &&
  499.               aptr->pixel.x - x >= 0 &&
  500.               aptr->pixel.x - x < width &&
  501.               aptr->pixel.y - y >= 0 &&
  502.               aptr->pixel.y - y < height)
  503.             {
  504.               mptr->chew = 1;
  505.               aptr->chewed = 1;
  506.               break;
  507.             }
  508.             }
  509.         }
  510.         /*}}}*/
  511.           }
  512.           /*}}}*/
  513.           break;
  514.         }
  515.         /*}}}*/
  516.         /*{{{  default:*/
  517.         default:
  518.           assert(0);
  519.           break;
  520.         /*}}}*/
  521.       }
  522.     }
  523.     }
  524.   monster.nearest = nearest;
  525.   monster.farthest = farthest;
  526.   return;
  527. }
  528. /*}}}*/
  529. /*{{{  void new_xtra()*/
  530. extern void new_xtra FUNCARGVOID
  531. /*
  532.  * increments the extra monster, and draws it up
  533.  */
  534. {
  535.   draw_extra_letter(extra.select);
  536.   if(extra.select == 4)
  537.     extra.select = 0;
  538.   else
  539.     extra.select++;
  540.   create_xtra_monster(extra.select);
  541.   draw_extra();
  542.   return;
  543. }
  544. /*}}}*/
  545. /*{{{  MONSTER *spawn_monster(type, dir, face, cx, cy, ox, oy)*/
  546. extern MONSTER *spawn_monster FUNCARGLIST((type, dir, face, cx, cy, ox, oy))
  547. int       type  FUNCARGSEP  /* type of monster 0-4 */
  548. int       dir   FUNCARGSEP  /* direction 0-3 */
  549. int       face  FUNCARGSEP  /* face 0-5 */
  550. int       cx    FUNCARGSEP  /* cell x */
  551. int       cy    FUNCARGSEP  /* cell y */
  552. int       ox    FUNCARGSEP  /* offset x */
  553. int       oy    FUNCARGTERM /* offset y */
  554. /*
  555.  * creates a new monster onto the monster list
  556.  * returns a pointer to the new monster
  557.  */
  558. {
  559.   MONSTER *mptr;
  560.  
  561.   assert(monster.monsters != MONSTERS);
  562.   assert(!(ox % VEL_X) && !(oy % VEL_Y));
  563.   mptr = &monster.list[monster.monsters++];
  564.   mptr->dir = dir;
  565.   mptr->type = type;
  566.   mptr->face = face;
  567.   mptr->apple = NULL;
  568.   mptr->push = 0;
  569.   mptr->gomunch = mptr->cont = mptr->chew = mptr->pause = mptr->stop = 0;
  570.   mptr->fast = mptr->pushing = 0;
  571.   mptr->count = 0;
  572.   mptr->cell.x = cx;
  573.   mptr->cell.y = cy;
  574.   mptr->offset.x = ox;
  575.   mptr->offset.y = oy;
  576.   mptr->pixel.x = PIXELX(cx, ox);
  577.   mptr->pixel.y = PIXELY(cy, oy);
  578.   mptr->image = random() % MONSTER_IMAGES;
  579.   mptr->cycle = random() % MONSTER_CYCLES;
  580.   mptr->shot = 0;
  581.   mptr->old_sprite = 0;
  582.   return mptr;
  583. }
  584. /*}}}*/
  585.